﻿using System;
using System.Collections.Generic;
using System.Linq;
using CITPRO.Linq.LinqToOdbc.SqlQueryGeneration;
using Remotion.Linq;
using System.Data;
using System.Data.Odbc;

namespace CITPRO.Linq.LinqToOdbc {
    public class DefaultOdbcQueryExecutor : IOdbcQueryExecutor {
        private readonly IOdbcReaderConvertor readerConvertor;
        private readonly IDialectProvider dialectProvider;
        private readonly ISqlRecorder sqlRecorder;
        private OdbcConnection connection;

        public DefaultOdbcQueryExecutor(IOdbcReaderConvertor readerConvertor, IDialectProvider dialectProvider, ISqlRecorder sqlRecorder = null) {
            this.readerConvertor = readerConvertor;
            this.dialectProvider = dialectProvider;
            this.sqlRecorder = sqlRecorder;
        }
        public virtual IEnumerable<T> ExecuteCollection<T>(QueryModel queryModel) {
            var sql = QueryModelVisitor.GenerateSqlQuery(queryModel, dialectProvider);
            if (sqlRecorder != null) sqlRecorder.Record(sql);
            var cmd = new OdbcCommand(sql, connection);
            var reader = cmd.ExecuteReader(CommandBehavior.CloseConnection);
            var result = readerConvertor.GetList<T>(reader);
            return result;
        }

        public void SetConnection(OdbcConnection odbcConnection) {
            connection = odbcConnection;
        }

        public virtual T ExecuteScalar<T>(QueryModel queryModel) {
            return ExecuteSingle<T>(queryModel, true);
        }

        public virtual T ExecuteSingle<T>(QueryModel queryModel, bool returnDefaultWhenEmpty) {

            return returnDefaultWhenEmpty ? ExecuteCollection<T>(queryModel).SingleOrDefault() : ExecuteCollection<T>(queryModel).Single();
        }

        public void Dispose() {
        }
    }
}
